package tools.cookietools;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.cookie.BasicClientCookie;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static java.util.Objects.nonNull;
import static lombok.AccessLevel.NONE;
import static lombok.AccessLevel.PROTECTED;

@Getter
@Setter(PROTECTED)
@AllArgsConstructor
@Builder
@NoArgsConstructor(access = PROTECTED)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ReadOnlyCookie implements ClientCookie {

    @NonNull
    private String name;
    private String value;
    private String domain;
    private String path;
    private Date expiryDate;
    private boolean isSecure;
    private String comment;
    @Builder.Default
    private int version = 0;
    @Getter(NONE)
    @Setter(NONE)
    private final Map<String, String> attribs = new HashMap<>();

    public ReadOnlyCookie(@NonNull String name, String value, String domain, String path) {
        this.name = name;
        this.value = value;
        this.domain = domain;
        this.path = path;
    }

    public ReadOnlyCookie(@NonNull Cookie cookie) {
        this(
            cookie.getName(),
            cookie.getValue(),
            cookie.getDomain(),
            cookie.getPath(),
            cookie.getExpiryDate(),
            cookie.isSecure(),
            cookie.getComment(),
            cookie.getVersion()
        );
        if (cookie instanceof ClientCookie) {
            applyAttributes((ClientCookie) cookie);
        }
    }

    private final String[] attributeKeys = new String[]{
        "httponly", VERSION_ATTR, PATH_ATTR, DOMAIN_ATTR, MAX_AGE_ATTR, SECURE_ATTR, COMMENT_ATTR,
        EXPIRES_ATTR, PORT_ATTR, COMMENTURL_ATTR, DISCARD_ATTR
    };

    protected void applyAttributes(ClientCookie cookie) {
        CookieUtils.getAttributes(cookie)
            .forEach(attribs::put);
    }

    public BasicClientCookie toBasicClientCookie() {
        BasicClientCookie cookie = new BasicClientCookie(name, value);
        cookie.setDomain(domain);
        cookie.setPath(path);
        cookie.setVersion(version);
        cookie.setSecure(isSecure);
        cookie.setExpiryDate(expiryDate);
        cookie.setComment(comment);
        this.attribs.forEach(cookie::setAttribute);
        return cookie;
    }

    @Override
    public String getAttribute(String name) {
        return this.attribs.get(name);
    }

    @Override
    public boolean containsAttribute(String name) {
        return this.attribs.containsKey(name);
    }

    @Override
    public String getCommentURL() {
        return null;
    }

    @Override
    @JsonIgnore
    public boolean isPersistent() {
        return (null != expiryDate);
    }

    @Override
    public int[] getPorts() {
        return null;
    }

    @Override
    @JsonIgnore
    public boolean isExpired(@NonNull Date date) {
        return (expiryDate != null
            && expiryDate.getTime() <= date.getTime());
    }

    protected ReadOnlyCookie setAttribs(Map<String, String> attribs) {
        if (nonNull(attribs)) {
            this.attribs.clear();
            attribs.forEach(this.attribs::put);
        }
        return this;
    }
}

